package com.towa.ninemanmorris;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.Toast;

import com.towa.ninemanmorris.R;

public class NineManMorrisView extends View {

	private Drawable backgroundImage; // Background image
	private Drawable[] reds; // Red markers
	private Drawable[] blues; // Blue markers
	private Drawable drawAnimation;
	private int redsOnBoard;
	private int bluesOnBoard;
	private NineManMorrisActivity activity;
	private Rect[] clickZones;
	private int currentPlayer;
	private static final int PLAYER_ONE = 1;
	private static final int PLAYER_TWO = 2;
	private static final int MARKERS_EASY = 9;
	private static int DIFFICULTY = 0;
	// private static final int MARKERS_MEDIUM = 7;
	// private static final int MARKERS_HARD = 6;
	private Animation animation;
	private int fromZone;
	private int toZone;
	private boolean touchDown;
	private ImageView red, blue;
	private int redsPlaced, bluesPlaced;
	private int[] gamefield;
	private boolean isRemove;
	private boolean updated;
	private RefreshHandler redrawHandler;
	private GameStatusWrapper gsw;
	private boolean loadGame;
	private int playerOneWins, playerTwoWins;

	public NineManMorrisView(Context context) {
		super(context);
		this.activity = (NineManMorrisActivity) context;

		DIFFICULTY = MARKERS_EASY;

		touchDown = false;
		gamefield = new int[25];
		updated = true;
		loadGame = false;
		redrawHandler = new RefreshHandler();

		// Get image resources
		backgroundImage = context.getResources().getDrawable(
				R.drawable.ninemenmorris300);
		reds = new Drawable[DIFFICULTY];
		blues = new Drawable[DIFFICULTY];
		for (int i = 0; i < DIFFICULTY; i++)
			reds[i] = context.getResources().getDrawable(R.drawable.red);
		for (int i = 0; i < DIFFICULTY; i++)
			blues[i] = context.getResources().getDrawable(R.drawable.blue);

		red = new ImageView(context);
		blue = new ImageView(context);

		redsOnBoard = 0;
		bluesOnBoard = 0;
		redsPlaced = 0;
		bluesPlaced = 0;

		isRemove = false;

		// Initiate click zones
		clickZones = new Rect[25];
		clickZones[0] = new Rect(0, 0, 0, 0);
		for (int i = 1; i < 25; i++) {
			clickZones[i] = new Rect(0, 0, 40, 40);
		}

		// Set player to start
		currentPlayer = PLAYER_ONE;

		// Load Game
		// loadGame = true;
		// this.gsw = gsw;
		// redrawHandler.sleep(5);
	}
	
	public synchronized void loadGame(GameStatusWrapper gsw){
		loadGame = true;
		this.gsw = gsw;
		Log.i("NineMenMorris", "Load: " + gsw.toString());
		currentPlayer = gsw.getPlayer();
		redsOnBoard = gsw.getRedsOnBoard();
		bluesOnBoard = gsw.getBluesOnBoard();
		redsPlaced = gsw.getRedsPlaced();
		bluesPlaced = gsw.getBluesPlaced();

		int[] redMarkers = gsw.getRedMarkers();
		for (int i = 0; i < redMarkers.length; i++) {
			gamefield[redMarkers[i]] = PLAYER_ONE;
		}

		int[] blueMarkers = gsw.getBlueMarkers();
		for (int i = 0; i < blueMarkers.length; i++) {
			gamefield[blueMarkers[i]] = PLAYER_TWO;
		}
		loadGame();
		invalidate();
	}
	
	private void loadGame() {
		int[] redMarkers = saveGameHelper(PLAYER_ONE);
		for(int i = 0; i < redMarkers.length; i++){
			reds[i].setBounds(clickZones[redMarkers[i]]);
		}
		
		int[] blueMarkers = saveGameHelper(PLAYER_TWO);
		for(int i = 0; i < blueMarkers.length; i++){
			blues[i].setBounds(clickZones[blueMarkers[i]]);
		}
		String s = "Load: ";
		for(int i = 1; i < 25; i++)
			s += gamefield[i] + ", ";
		Log.i("ymmot", s);
	}

public synchronized GameStatusWrapper saveGame(String name){
		GameStatusWrapper gsw = new GameStatusWrapper();
		gsw.setId(this.gsw.getId());
		gsw.setGameName(name);
		gsw.setPlayer(currentPlayer);
		gsw.setRedsOnBoard(redsOnBoard);
		gsw.setBluesOnBoard(bluesOnBoard);
		gsw.setRedsPlaced(redsPlaced);
		gsw.setBluesPlaced(bluesPlaced);
		gsw.setRedMarkers(saveGameHelper(PLAYER_ONE));
		gsw.setBlueMarkers(saveGameHelper(PLAYER_TWO));
		Log.i("NineMenMorris", "Save: " + gsw.toString());
		String s = "Save: ";
		for(int i = 1; i < 25; i++)
			s += gamefield[i] + ", ";
		Log.i("ymmot", s);
		return gsw;
	}

	private int[] saveGameHelper(int player) {
		int[] markers = new int[9];
		int k = 0;
		for (int i = 1; i < gamefield.length; i++) {
			if (gamefield[i] == player) {
				markers[k] = i;
				k++;
			}
		}
		return markers;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		backgroundImage.setBounds(new Rect(0, 0, getWidth(), getHeight()));
		backgroundImage.draw(canvas);
		updateClickZonesLocation();
//		loadGame();
		for (int i = 0; i < DIFFICULTY; i++) {
			reds[i].draw(canvas);
			blues[i].draw(canvas);
		}
		Paint red = new Paint();
		red.setColor(Color.RED);
		red.setStyle(Style.FILL);
		red.setTextSize(35);
		if (currentPlayer == PLAYER_ONE) {
			red.setUnderlineText(true);
		} else {
			red.setUnderlineText(false);
		}
		Paint blue = new Paint();
		blue.setColor(Color.BLUE);
		blue.setStyle(Style.FILL);
		blue.setTextSize(35);
		if (currentPlayer == PLAYER_TWO) {
			blue.setUnderlineText(true);
		} else {
			blue.setUnderlineText(false);
		}
		canvas.drawText("Player one: " + redsOnBoard, 25, 35, red);
		canvas.drawText("Player two: " + bluesOnBoard, (canvas.getWidth() / 2),
				35, blue);
		updateClickZonesLocation();
		if (loadGame) {
			loadGame();
			loadGame = false;
			invalidate();
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int zone = getClickZone((int) event.getX(), (int) event.getY());
		if (zone != 0 && updated) {
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				// Log.i("NineManMorris", "action_down");
				break;
			case MotionEvent.ACTION_MOVE:
				if (!touchDown) {
					touchDown = true;
					setFromZone(zone);
					// Log.i("NineManMorris", "from zone: " + zone);
				}
				break;
			case MotionEvent.ACTION_UP:
				if (isRemove) {
					removeMarker(zone);
				} else {
					if (redsPlaced != DIFFICULTY && currentPlayer == PLAYER_ONE) {
						placeMarker(zone, currentPlayer);
						if (isThreeInRow(zone)) {
							currentPlayer = PLAYER_ONE;
							isRemove = true;
						}
					} else if (bluesPlaced != DIFFICULTY
							&& currentPlayer == PLAYER_TWO) {
						placeMarker(zone, currentPlayer);
						if (isThreeInRow(zone)) {
							currentPlayer = PLAYER_TWO;
							isRemove = true;
						}
					} else {
						touchDown = false;
						setToZone(zone);
						// Log.i("NineManMorris", "to zone: " + zone);
						startMyAnimation();
					}
				}
				if (redsPlaced == DIFFICULTY && bluesPlaced == DIFFICULTY) {
					switch (win()) {
					case PLAYER_ONE:
						Log.i("NineManMorris", "Player one wins!");
						updateWinRatio(PLAYER_ONE);
						AlertDialog.Builder winner = new AlertDialog.Builder(
								getContext());
						winner.setTitle("Winner!");
						winner.setMessage("Player One Wins!");
						winner.setPositiveButton("Back to menu",
								new DialogInterface.OnClickListener() {
									public void onClick(DialogInterface dialog,
											int which) {
										activity.returnToMenu();
									}
								});
						winner.show();
						break;
					case PLAYER_TWO:
						Log.i("NineManMorris", "Player two wins!");
						updateWinRatio(PLAYER_ONE);
						AlertDialog.Builder winner2 = new AlertDialog.Builder(
								getContext());
						winner2.setTitle("Winner!");
						winner2.setMessage("Player Two Wins!");
						winner2.setPositiveButton("Back to menu",
								new DialogInterface.OnClickListener() {
									public void onClick(DialogInterface dialog,
											int which) {
										activity.returnToMenu();
									}
								});
						winner2.show();
						break;
					}
				}
				break;
			}
		}
		activity.setTitle("Player " + currentPlayer);
		invalidate();
		return true;
	}

	private void updateWinRatio(int player) {
		// POST to the server that someone has won and that the info needs updating
		if (player == PLAYER_ONE) {
			// Player one won. Send info about this
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
			new Tasker().doInBackground("score::" + prefs.getString("playerOne", "dummy") + "::1::0");
			new Tasker().doInBackground("score::" + prefs.getString("playerTwo", "dummy") + "::0::1");
		} else if (player == PLAYER_TWO) {
			// Player two won. Send info about this
			SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
			new Tasker().doInBackground("score::" + prefs.getString("playerTwo", "dummy") + "::1::0");
			new Tasker().doInBackground("score::" + prefs.getString("playerOne", "dummy") + "::0::1");
		}
	}

	private void startMyAnimation() {
		animation = new TranslateAnimation(clickZones[fromZone].centerX(), // From
																			// x
				clickZones[toZone].centerX(), // To x
				clickZones[fromZone].centerY(), // From y
				clickZones[toZone].centerY()); // To y
		animation.setDuration(10000);
		animation.setInterpolator(new AccelerateDecelerateInterpolator());

		if (currentPlayer == PLAYER_ONE) {
			int marker = getRedMarkerInZone(fromZone);
			if (marker != -1) {
				moveMarker(marker, fromZone, toZone);
				red.setImageDrawable(reds[marker]);
				red.startAnimation(animation);
				red.setImageResource(R.drawable.red);
			}
		} else if (currentPlayer == PLAYER_TWO) {
			int marker = getBlueMarkerInZone(fromZone);
			if (marker != -1) {
				moveMarker(marker, fromZone, toZone);
				blue.setImageDrawable(blues[marker]);
				blue.startAnimation(animation);
				blue.setImageResource(R.drawable.red);
			}
		}
	}

	private void setToZone(int zone) {
		toZone = zone;
	}

	private void setFromZone(int zone) {
		fromZone = zone;
	}

	private int getClickZone(int x, int y) {
		int click = 0;
		for (int i = 1; i < 25; i++) {
			if (clickZones[i].contains(x, y)) {
				click = i;
				break;
			}
		}
		return click;
	}

	private int getRedMarkerInZone(int zone) {
		for (int i = 0; i < DIFFICULTY; i++) {
			if (reds[i].getBounds().equals(clickZones[zone])) {
				return i;
			}
		}
		return -1;
	}

	private int getBlueMarkerInZone(int zone) {
		for (int i = 0; i < DIFFICULTY; i++) {
			if (blues[i].getBounds().equals(clickZones[zone])) {
				return i;
			}
		}
		return -1;
	}

	private void moveMarker(int marker, int fromZone, int toZone) {
		if (isValidMove(toZone, fromZone)) {
			if (fromZone != toZone && toZone != 0 && isZoneAvailable(toZone)) {
				if (currentPlayer == PLAYER_ONE) {
					// reds[marker].setBounds(clickZones[toZone]);
					doAnimation(reds[marker]);
					gamefield[fromZone] = 0;
					gamefield[toZone] = PLAYER_ONE;
					if (isThreeInRow(toZone)) {
						isRemove = true;
						currentPlayer = PLAYER_ONE;
					} else
						currentPlayer = PLAYER_TWO;
				} else if (currentPlayer == PLAYER_TWO) {
					// blues[marker].setBounds(clickZones[toZone]);
					doAnimation(blues[marker]);
					gamefield[fromZone] = 0;
					gamefield[toZone] = PLAYER_TWO;
					if (isThreeInRow(toZone)) {
						isRemove = true;
						currentPlayer = PLAYER_TWO;
					} else
						currentPlayer = PLAYER_ONE;
				}
			}
		}
	}

	class RefreshHandler extends Handler {

		@Override
		public void handleMessage(Message msg) {
			NineManMorrisView.this.update();
			NineManMorrisView.this.invalidate();
		}

		public void sleep(long delayMillis) {
			this.removeMessages(0);
			sendMessageDelayed(obtainMessage(0), delayMillis);
		}
	};

	public void update() {
		Rect move = clickZones[0];
		Rect to = clickZones[toZone];

		if (!to.contains(move) && drawAnimation != null) {
			int x = 0;
			int y = 0;
			if (to.centerX() > move.centerX()) {
				x++;
			} else if (to.centerX() < move.centerX()) {
				x--;
			}

			if (to.centerY() > move.centerY()) {
				y++;
			} else if (to.centerY() < move.centerY()) {
				y--;
			}

			move.offset(x, y);
			drawAnimation.setBounds(move);
			redrawHandler.sleep(0);
		} else {
			if (drawAnimation != null)
				drawAnimation.setBounds(to);
			updated = true;
			drawAnimation = null;
			invalidate();
		}
	}

	private void doAnimation(Drawable d) {
		drawAnimation = d;
		clickZones[0].set(clickZones[fromZone]);
		updated = false;
		update();
	}

	private boolean isZoneAvailable(int zone) {
		for (int i = 0; i < DIFFICULTY; i++) {
			if (clickZones[zone].contains(reds[i].getBounds())) {
				return false;
			}
			if (clickZones[zone].contains(blues[i].getBounds())) {
				return false;
			}
		}
		return true;
	}

	private void placeMarker(int zone, int player) {
		if (zone != 0) {
			if (player == PLAYER_ONE) {
				if (redsOnBoard < DIFFICULTY) {
					if (isZoneAvailable(zone)) {
						reds[redsOnBoard].setBounds(clickZones[zone]);
						gamefield[zone] = PLAYER_ONE;
						redsOnBoard++;
						redsPlaced++;
						currentPlayer = PLAYER_TWO;
					}
				}
			} else if (player == PLAYER_TWO) {
				if (bluesOnBoard < DIFFICULTY + 1) {
					if (isZoneAvailable(zone)) {
						blues[bluesOnBoard].setBounds(clickZones[zone]);
						gamefield[zone] = PLAYER_TWO;
						bluesOnBoard++;
						bluesPlaced++;
						currentPlayer = PLAYER_ONE;
					}
				}
			}
		}
	}

	private void removeMarker(int zone) {
		Log.i("NineManMorris", "Removing from zone: " + zone);
		if (currentPlayer == PLAYER_ONE) {
			if (getBlueMarkerInZone(zone) != -1) {
				blues[getBlueMarkerInZone(zone)].setBounds(-10, -10, -5, -5);
				bluesOnBoard--;
				currentPlayer = PLAYER_TWO;
				isRemove = false;
				gamefield[zone] = 0;
			}
		} else if (currentPlayer == PLAYER_TWO) {
			if (getRedMarkerInZone(zone) != -1) {
				reds[getRedMarkerInZone(zone)].setBounds(-10, -10, -5, -5);
				redsOnBoard--;
				currentPlayer = PLAYER_ONE;
				isRemove = false;
				gamefield[zone] = 0;
			}
		}
	}

	private void updateClickZonesLocation() {
		int X_START = getWidth() / 2;
		int Y_START = getHeight() / 2;
		clickZones[1].offsetTo(X_START - 65, Y_START - 65);
		clickZones[2].offsetTo(X_START - 111, Y_START - 111);
		clickZones[3].offsetTo(X_START - 157, Y_START - 157);
		clickZones[4].offsetTo(X_START - 20, Y_START - 65);
		clickZones[5].offsetTo(X_START - 20, Y_START - 111);
		clickZones[6].offsetTo(X_START - 20, Y_START - 157);
		clickZones[7].offsetTo(X_START + 25, Y_START - 65);
		clickZones[8].offsetTo(X_START + 71, Y_START - 111);
		clickZones[9].offsetTo(X_START + 117, Y_START - 157);
		clickZones[10].offsetTo(X_START + 25, Y_START - 20);
		clickZones[11].offsetTo(X_START + 71, Y_START - 20);
		clickZones[12].offsetTo(X_START + 117, Y_START - 20);
		clickZones[13].offsetTo(X_START + 25, Y_START + 25);
		clickZones[14].offsetTo(X_START + 71, Y_START + 71);
		clickZones[15].offsetTo(X_START + 117, Y_START + 117);
		clickZones[16].offsetTo(X_START - 20, Y_START + 25);
		clickZones[17].offsetTo(X_START - 20, Y_START + 71);
		clickZones[18].offsetTo(X_START - 20, Y_START + 117);
		clickZones[19].offsetTo(X_START - 65, Y_START + 25);
		clickZones[20].offsetTo(X_START - 111, Y_START + 71);
		clickZones[21].offsetTo(X_START - 157, Y_START + 117);
		clickZones[22].offsetTo(X_START - 65, Y_START - 20);
		clickZones[23].offsetTo(X_START - 111, Y_START - 20);
		clickZones[24].offsetTo(X_START - 157, Y_START - 20);
	}

	public boolean isThreeInRow(int to) {
		if ((to == 1 || to == 4 || to == 7) && gamefield[1] == gamefield[4]
				&& gamefield[4] == gamefield[7]) {
			return true;
		} else if ((to == 2 || to == 5 || to == 8)
				&& gamefield[2] == gamefield[5] && gamefield[5] == gamefield[8]) {
			return true;
		} else if ((to == 3 || to == 6 || to == 9)
				&& gamefield[3] == gamefield[6] && gamefield[6] == gamefield[9]) {
			return true;
		} else if ((to == 7 || to == 10 || to == 13)
				&& gamefield[7] == gamefield[10]
				&& gamefield[10] == gamefield[13]) {
			return true;
		} else if ((to == 8 || to == 11 || to == 14)
				&& gamefield[8] == gamefield[11]
				&& gamefield[11] == gamefield[14]) {
			return true;
		} else if ((to == 9 || to == 12 || to == 15)
				&& gamefield[9] == gamefield[12]
				&& gamefield[12] == gamefield[15]) {
			return true;
		} else if ((to == 13 || to == 16 || to == 19)
				&& gamefield[13] == gamefield[16]
				&& gamefield[16] == gamefield[19]) {
			return true;
		} else if ((to == 14 || to == 17 || to == 20)
				&& gamefield[14] == gamefield[17]
				&& gamefield[17] == gamefield[20]) {
			return true;
		} else if ((to == 15 || to == 18 || to == 21)
				&& gamefield[15] == gamefield[18]
				&& gamefield[18] == gamefield[21]) {
			return true;
		} else if ((to == 1 || to == 22 || to == 19)
				&& gamefield[1] == gamefield[22]
				&& gamefield[22] == gamefield[19]) {
			return true;
		} else if ((to == 2 || to == 23 || to == 20)
				&& gamefield[2] == gamefield[23]
				&& gamefield[23] == gamefield[20]) {
			return true;
		} else if ((to == 3 || to == 24 || to == 21)
				&& gamefield[3] == gamefield[24]
				&& gamefield[24] == gamefield[21]) {
			return true;
		} else if ((to == 22 || to == 23 || to == 24)
				&& gamefield[22] == gamefield[23]
				&& gamefield[23] == gamefield[24]) {
			return true;
		} else if ((to == 4 || to == 5 || to == 6)
				&& gamefield[4] == gamefield[5] && gamefield[5] == gamefield[6]) {
			return true;
		} else if ((to == 10 || to == 11 || to == 12)
				&& gamefield[10] == gamefield[11]
				&& gamefield[11] == gamefield[12]) {
			return true;
		} else if ((to == 16 || to == 17 || to == 18)
				&& gamefield[16] == gamefield[17]
				&& gamefield[17] == gamefield[18]) {
			return true;
		}
		return false;
	}

	private int win() {
		if (redsOnBoard == 2) {
			return PLAYER_TWO;
		}
		if (bluesOnBoard == 2) {
			return PLAYER_ONE;
		}
		int red = 0;
		int blue = 0;
		for (int i = 1; i < 25; i++) {
			if (hasValidMove(i)) {
				if (gamefield[i] == PLAYER_ONE) {
					red++;
				} else if (gamefield[i] == PLAYER_TWO) {
					blue++;
				}
			}
		}
		if (isRemove) {
			return 0;
		}
		if (red == 0) {
			return PLAYER_TWO;
		}
		if (blue == 0) {
			return PLAYER_ONE;
		}
		return 0;
	}

	// From pos
	private boolean hasValidMove(int pos) {
		switch (pos) {
		case 1:
			if (gamefield[4] == 0 || gamefield[22] == 0)
				return true;
			break;
		case 2:
			if (gamefield[5] == 0 || gamefield[23] == 0)
				return true;
			break;
		case 3:
			if (gamefield[6] == 0 || gamefield[24] == 0)
				return true;
			break;
		case 4:
			if (gamefield[1] == 0 || gamefield[5] == 0 || gamefield[7] == 0)
				return true;
			break;
		case 5:
			if (gamefield[2] == 0 || gamefield[4] == 0 || gamefield[6] == 0
					|| gamefield[8] == 0)
				return true;
			break;
		case 6:
			if (gamefield[3] == 0 || gamefield[5] == 0 || gamefield[9] == 0)
				return true;
			break;
		case 7:
			if (gamefield[4] == 0 || gamefield[10] == 0)
				return true;
			break;
		case 8:
			if (gamefield[5] == 0 || gamefield[11] == 0)
				return true;
			break;
		case 9:
			if (gamefield[6] == 0 || gamefield[12] == 0)
				return true;
			break;
		case 10:
			if (gamefield[7] == 0 || gamefield[11] == 0 || gamefield[13] == 0)
				return true;
			break;
		case 11:
			if (gamefield[8] == 0 || gamefield[10] == 0 || gamefield[12] == 0
					|| gamefield[14] == 0)
				return true;
			break;
		case 12:
			if (gamefield[9] == 0 || gamefield[11] == 0 || gamefield[15] == 0)
				return true;
			break;
		case 13:
			if (gamefield[10] == 0 || gamefield[16] == 0)
				return true;
			break;
		case 14:
			if (gamefield[11] == 0 || gamefield[17] == 0)
				return true;
			break;
		case 15:
			if (gamefield[12] == 0 || gamefield[18] == 0)
				return true;
			break;
		case 16:
			if (gamefield[13] == 0 || gamefield[17] == 0 || gamefield[19] == 0)
				return true;
			break;
		case 17:
			if (gamefield[14] == 0 || gamefield[16] == 0 || gamefield[18] == 0
					|| gamefield[20] == 0)
				return true;
			break;
		case 18:
			if (gamefield[15] == 0 || gamefield[17] == 0 || gamefield[21] == 0)
				return true;
			break;
		case 19:
			if (gamefield[16] == 0 || gamefield[22] == 0)
				return true;
			break;
		case 20:
			if (gamefield[17] == 0 || gamefield[23] == 0)
				return true;
			break;
		case 21:
			if (gamefield[18] == 0 || gamefield[24] == 0)
				return true;
			break;
		case 22:
			if (gamefield[1] == 0 || gamefield[19] == 0 || gamefield[23] == 0)
				return true;
			break;
		case 23:
			if (gamefield[2] == 0 || gamefield[20] == 0 || gamefield[22] == 0
					|| gamefield[24] == 0)
				return true;
			break;
		case 24:
			if (gamefield[3] == 0 || gamefield[21] == 0 || gamefield[23] == 0)
				return true;
			break;
		}
		return false;
	}

	private boolean isValidMove(int to, int from) {

		switch (to) {
		case 1:
			return (from == 4 || from == 22);
		case 2:
			return (from == 5 || from == 23);
		case 3:
			return (from == 6 || from == 24);
		case 4:
			return (from == 1 || from == 7 || from == 5);
		case 5:
			return (from == 4 || from == 6 || from == 2 || from == 8);
		case 6:
			return (from == 3 || from == 5 || from == 9);
		case 7:
			return (from == 4 || from == 10);
		case 8:
			return (from == 5 || from == 11);
		case 9:
			return (from == 6 || from == 12);
		case 10:
			return (from == 11 || from == 7 || from == 13);
		case 11:
			return (from == 10 || from == 12 || from == 8 || from == 14);
		case 12:
			return (from == 11 || from == 15 || from == 9);
		case 13:
			return (from == 16 || from == 10);
		case 14:
			return (from == 11 || from == 17);
		case 15:
			return (from == 12 || from == 18);
		case 16:
			return (from == 13 || from == 17 || from == 19);
		case 17:
			return (from == 14 || from == 16 || from == 20 || from == 18);
		case 18:
			return (from == 17 || from == 15 || from == 21);
		case 19:
			return (from == 16 || from == 22);
		case 20:
			return (from == 17 || from == 23);
		case 21:
			return (from == 18 || from == 24);
		case 22:
			return (from == 1 || from == 19 || from == 23);
		case 23:
			return (from == 22 || from == 2 || from == 20 || from == 24);
		case 24:
			return (from == 3 || from == 21 || from == 23);
		}
		return false;
	}
}
